﻿using System;
using System.Drawing;

namespace Job.Core.Imaging
{
    /// <summary>
    /// 用于生成验证码图像(无法继承此类)。
    /// </summary>
    public sealed class ValidateCode
    {
        #region Properties

        /// <summary>
        /// 宽度。
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// 高度。
        /// </summary>
        public int Height { get; set; }

        /// <summary>
        /// 验证文字。
        /// </summary>
        public string Text { get; set ;}

        /// <summary>
        /// 字体大小。
        /// </summary>
        public int FontSize { get; set; }

        /// <summary>
        /// 字体名称。
        /// </summary>
        public string[] FontNames { get; set; }

        /// <summary>
        /// 字体颜色。
        /// </summary>
        public Color[] FontColors { get; set; }

        /// <summary>
        /// 干扰线。
        /// </summary>
        public int NoiseLine { get; set; }

        /// <summary>
        /// 干扰点。
        /// </summary>
        public int NoisePoint { get; set; }

        /// <summary>
        /// 背景颜色。
        /// </summary>
        public Color BackgroudColor { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// 初始化 ValidateCode 的新实例。
        /// </summary>
        /// <param name="width">图像宽度。</param>
        /// <param name="height">图像高度。</param>
        /// <param name="text">验证码。</param>       
        /// <param name="fontNames">字体名称。</param>
        /// <param name="fontSize">字体大小。</param>
        /// <param name="fontColors">字体颜色。</param>
        /// <param name="noiseLine">干扰线条数量。</param>
        /// <param name="noisePoint">干扰噪点数量。</param>
        /// <param name="backgroudColor">背景颜色。</param>
        public ValidateCode(int width, int height, string text, string[] fontNames, int fontSize, Color[] fontColors, int noiseLine, int noisePoint, Color backgroudColor)
        {
            Width = width;
            Height = height;
            Text = text;           
            FontNames = fontNames;
            FontSize = fontSize;
            FontColors = fontColors;
            NoiseLine = noiseLine;
            NoisePoint = noisePoint;
            BackgroudColor = backgroudColor;
        }

        /// <summary>
        /// 初始化 ValidateCode 的新实例。
        /// </summary>
        /// <param name="width">图像宽度。</param>
        /// <param name="height">图像高度。</param>
        /// <param name="text">验证码。</param>       
        /// <param name="noiseLine">干扰线条数量。</param>
        /// <param name="noisePoint">干扰噪点数量。</param>
        public ValidateCode(int width, int height, string text, int noiseLine, int noisePoint)
            : this(width, height, text, new string[] { "Arial", "System" }, 12, new Color[] { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple }, noiseLine, noisePoint, Color.White)
        {
        }

        /// <summary>
        /// 初始化 ValidateCode 的新实例。
        /// </summary>
        /// <param name="width">图像宽度。</param>
        /// <param name="height">图像高度。</param>
        /// <param name="text">验证码。</param>
        public ValidateCode(int width, int height, string text)
            : this(width, height, text, 0, 100)
        {
        }

        #endregion

        #region Methods

        /// <summary>
        /// 生成验证码图像。
        /// </summary>
        /// <param name="image">验证码图像。</param>
        public Image CreateImage()
        {
            Graphics g = null;
            Image image = new Bitmap(Width, Height);

            try
            {               
                //生成随机生成器 
                Random random = new Random();

                g = Graphics.FromImage(image);

                //清空图片背景色 
                g.Clear(BackgroudColor);

                //画图片干扰线 
                for (int i = 0; i < NoiseLine; i++)
                {
                    int x1 = random.Next(image.Width);
                    int x2 = random.Next(image.Width);
                    int y1 = random.Next(image.Height);
                    int y2 = random.Next(image.Height);
                    g.DrawLine(new Pen(FontColors[random.Next(FontColors.Length)], 2), x1, y1, x2, y2);
                }

                //画图片干扰点
                Bitmap bitmap = image as Bitmap;
                if (bitmap != null)
                {
                    for (int i = 0; i < NoisePoint; i++)
                    {
                        int x = random.Next(image.Width);
                        int y = random.Next(image.Height);

                        bitmap.SetPixel(x, y, FontColors[random.Next(FontColors.Length)]);
                    }
                }

                //画验证码
                for (int i = 0; i < Text.Length; i++)
                {
                    string s = Text[i].ToString();

                    Font drawFont = null;
                    SolidBrush drawBrush = null;

                    try
                    {
                        drawFont = new Font(FontNames[random.Next(FontNames.Length)], FontSize, FontStyle.Bold);
                        drawBrush = new SolidBrush(FontColors[random.Next(FontColors.Length)]);

                        SizeF size = g.MeasureString(s, drawFont);
                        float offsetX = (image.Width - size.Width * Text.Length) / 2;
                        RectangleF drawRect = new RectangleF(i * size.Width + offsetX, random.Next(Math.Abs(image.Height - (int)size.Height)), size.Width, size.Height);

                        g.DrawString(s, drawFont, drawBrush, drawRect);
                    }
                    finally
                    {
                        if (drawBrush != null) drawBrush.Dispose();
                        if (drawFont != null) drawFont.Dispose();
                    }
                }

                //画图片的边框线 
                //g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
                return image;
            }
            finally
            {               
                if (g != null) g.Dispose();
            }
        }

        #endregion
    }
}